{
 "cells": [
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "# 神经网络解决分类问题的基本流程\n",
    "\n",
    "本节内容来自：[神经网络解决分类问题的基本流程](https://www.bilibili.com/video/BV1LT421v7Lw)\n",
    "\n",
    "节选了一些我认为可以解决我的疑惑的内容。\n",
    "\n",
    "## 为什么大家一开始采用 Sigmoid 作为激活函数？\n",
    "\n",
    "Sigmoid 函数的公式为：\n",
    "$\n",
    "\\sigma(x) = \\frac{1}{1 + e^{-x}}\n",
    "$\n",
    "\n",
    "一开始，人们尝试模仿大脑中的神经元使用\n",
    "$ f(x) =\n",
    "\\begin{cases}\n",
    "1, x > 0 \\\\\n",
    "0, x \\leq 0\n",
    "\\end{cases}\n",
    "$\n",
    "作为激活函数，即有输入激活，没输入不激活（或者是达到一个阈值进行输出），但是在后面的发展中，发现这种方式效果并不好。\n",
    "那为什么选用一个这么奇怪的函数作为激活函数呢？有什么数学原理或者细节呢？\n",
    "\n",
    "实际上，这是为了采用逻辑回归的建模成果。\n",
    "\n",
    "![](images/窗口效应和逻辑回归.png)\n",
    "\n",
    "逻辑回归是解决分类问题的经典模型，比如对于一件商品，我们是否购买就分为了两类，因此我们就可以使用逻辑回归模型来预测我们是否购买这件商品。\n",
    "\n",
    "在不可观察行为中，我们把是否购买的结果分解为正效应和负效应两个结果，实际上就是对应着不同两种决定因素，比如正效应就是我买了这个商品我可以获得良好的体验，负效应就是这件商品很贵。初次之外可能还有若干的正负效应叠加。\n",
    "\n",
    "当正 > 负的时候，我们就认为用户产生购买行为，反之则不会购买。上图中，我们把正负效应使用线性模型回归（因为这是我们已知的最简单的模型），他们互相竞争的一个过程可以用上图中最下面的公式进行表示。该公式中包含正态分布的累计函数，但是我们无法知道 $F_{\\epsilon}$ 确切的表示式子，于是我们只能去近似（为什么需要近似？当时的模型回归都是需要人来计算的，没有计算器所以尽可能需要用数学手段去近似它，在数值计算上可以减少计算量）。\n",
    "\n",
    "对于 $F_{\\epsilon}$ 的近似，我们发现，正态分布可以很好的用逻辑分布来近似，因此可以用逻辑分布来近似正态分布，这个逻辑分布就是 Sigmoid 。\n",
    "\n",
    "并且，这一实现让神经元的输出有了概率的意义，借鉴上述的逻辑回归的过程，我们可以知道这样一个概率的背后是条件竞争产生的结果。\n",
    "另外，Sigmoid 函数的值域范围在 (0, 1) ，一定程度上模拟了神经元的激活程度，比单纯的激活函数表示更丰富。"
   ],
   "id": "733607c7a758a611"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:27:19.890730Z",
     "start_time": "2025-08-13T12:26:49.820610Z"
    }
   },
   "cell_type": "code",
   "source": [
    "import torch\n",
    "\n",
    "torch.manual_seed(1024)"
   ],
   "id": "8391722ebc37c76a",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<torch._C.Generator at 0x1b3eb924c10>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 2
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:27:19.909807Z",
     "start_time": "2025-08-13T12:27:19.904249Z"
    }
   },
   "cell_type": "code",
   "source": [
    "### 手搓 Sigmoid\n",
    "\n",
    "# 唐一旦老师这边想要去模仿 Pytorch 去实现一个线性的链接层，其中 self.weight 中的 in_features, out_features 实际上就是每个神经元的全连接\n",
    "\n",
    "class Linear:\n",
    "    # input: (B, in_features)\n",
    "    # output: (B, out_features)\n",
    "\n",
    "    def __init__(self, in_features, out_features, bias=True):\n",
    "        \"\"\"\n",
    "        :param in_features: 输入神经元的个数\n",
    "        :param out_features: 输出神经元的个数\n",
    "        :param bias: 是否需要截距\n",
    "        \"\"\"\n",
    "        # 对于模型参数的初始化，故意没有做优化\n",
    "        self.weight = torch.randn(in_features, out_features, requires_grad=True)  # (in_features, out_features)\n",
    "        if bias:\n",
    "            self.bias = torch.randn(out_features, requires_grad=True)  # (             out_features)\n",
    "        else:\n",
    "            self.bias = None\n",
    "\n",
    "    def __call__(self, x):\n",
    "        # x:            (B, in_features)\n",
    "        # self.weight:  (in_features, out_features)\n",
    "        self.out = x @ self.weight  # (B, out_features)\n",
    "\n",
    "        if self.bias is not None:\n",
    "            self.out += self.bias\n",
    "\n",
    "        return self.out\n",
    "\n",
    "    def parameters(self):\n",
    "        # 返回模型参数\n",
    "        if self.bias is not None:\n",
    "            return self.weight, self.bias\n",
    "        return (self.weight,)\n"
   ],
   "id": "df148fd87b3548b7",
   "outputs": [],
   "execution_count": 3
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:27:20.010805Z",
     "start_time": "2025-08-13T12:27:19.916488Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 测试模型搭建是否符合预期\n",
    "l = Linear(3, 4)\n",
    "x = torch.randn(5, 3)\n",
    "print(l(x).shape)\n",
    "print(l.parameters())"
   ],
   "id": "c5a4954887c677e7",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([5, 4])\n",
      "(tensor([[-1.4837,  0.2671, -1.8337, -0.1047],\n",
      "        [ 0.6002, -0.5496,  1.0391,  0.2261],\n",
      "        [ 0.3490,  0.9540,  0.0909,  0.2139]], requires_grad=True), tensor([ 0.0137,  1.7289, -0.4150,  0.0753], requires_grad=True))\n"
     ]
    }
   ],
   "execution_count": 4
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:27:20.040136Z",
     "start_time": "2025-08-13T12:27:20.036550Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class Sigmoid:\n",
    "    def __call__(self, x):\n",
    "        self.out = torch.sigmoid(x)\n",
    "        return self.out\n",
    "\n",
    "    def parameters(self):\n",
    "        return tuple()"
   ],
   "id": "9c3f359268e75d3a",
   "outputs": [],
   "execution_count": 5
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:27:20.076911Z",
     "start_time": "2025-08-13T12:27:20.070506Z"
    }
   },
   "cell_type": "code",
   "source": [
    "s = Sigmoid()\n",
    "x = torch.randn(3, 2)\n",
    "s(x).shape"
   ],
   "id": "3230272d1c42f609",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([3, 2])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 6
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:27:20.095032Z",
     "start_time": "2025-08-13T12:27:20.091012Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class Perception:\n",
    "\n",
    "    def __init__(self, in_features):\n",
    "        self.ln = Linear(in_features, 1)\n",
    "        self.f = Sigmoid()\n",
    "\n",
    "    def __call__(self, x):\n",
    "        # x: (B, in_features)\n",
    "        self.out = self.f(self.ln(x))  # (B, 1)\n",
    "        return self.out\n",
    "\n",
    "    def parameters(self):\n",
    "        return self.ln.parameters() + self.f.parameters()"
   ],
   "id": "6ec3c5e05702e7d1",
   "outputs": [],
   "execution_count": 7
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:27:20.115293Z",
     "start_time": "2025-08-13T12:27:20.109791Z"
    }
   },
   "cell_type": "code",
   "source": [
    "p = Perception(3)\n",
    "x = torch.randn(5, 3)\n",
    "print(p(x).shape)"
   ],
   "id": "cee244b58b484cb7",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([5, 1])\n"
     ]
    }
   ],
   "execution_count": 8
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## Softmax 函数\n",
    "\n",
    "$$\n",
    "\\mathbf{Z} = (z_0, z_1, \\dots, z_{k-1}) => Softmax => \\left( \\frac{e^{z_0}}{\\sum_{j=0}^{k-1} e^{z_j}}, \\frac{e^{z_1}}{\\sum_{j=0}^{k-1} e^{z_j}}, \\dots, \\frac{e^{z_{k-1}}}{\\sum_{j=0}^{k-1} e^{z_j}} \\right)\n",
    "$$"
   ],
   "id": "b1c197e79377a804"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:27:20.176571Z",
     "start_time": "2025-08-13T12:27:20.172412Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class LogitRegression:\n",
    "    # input: (B, in_features)\n",
    "    # output: (B, 2)\n",
    "\n",
    "    def __init__(self, in_features):\n",
    "        self.pos = Linear(in_features, 1)\n",
    "        self.neg = Linear(in_features, 1)\n",
    "\n",
    "    def __call__(self, x):\n",
    "        # x: (B, in_features)\n",
    "        self.out = torch.concat([self.pos(x), self.neg(x)], dim=-1)  # (B, 2)\n",
    "        return self.out\n",
    "\n",
    "    def parameters(self):\n",
    "        return self.pos.parameters() + self.neg.parameters()"
   ],
   "id": "b25f026b67fc7ef4",
   "outputs": [],
   "execution_count": 9
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:27:20.189555Z",
     "start_time": "2025-08-13T12:27:20.184004Z"
    }
   },
   "cell_type": "code",
   "source": [
    "lr = LogitRegression(3)\n",
    "x = torch.randn(5, 3)\n",
    "print(lr(x).shape)"
   ],
   "id": "2119a2ef75f15a9",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([5, 2])\n"
     ]
    }
   ],
   "execution_count": 10
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:27:20.216809Z",
     "start_time": "2025-08-13T12:27:20.202401Z"
    }
   },
   "cell_type": "code",
   "source": [
    "import torch.nn.functional as F\n",
    "\n",
    "logits = lr(x)\n",
    "probs = F.softmax(logits, dim=-1)\n",
    "print(probs)\n",
    "\n",
    "# 每一行相加为 100%"
   ],
   "id": "d53f99b32f19f212",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[6.0937e-01, 3.9063e-01],\n",
      "        [8.8799e-01, 1.1201e-01],\n",
      "        [1.2545e-02, 9.8745e-01],\n",
      "        [5.4686e-01, 4.5314e-01],\n",
      "        [9.9931e-01, 6.9424e-04]], grad_fn=<SoftmaxBackward0>)\n"
     ]
    }
   ],
   "execution_count": 11
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:27:20.231594Z",
     "start_time": "2025-08-13T12:27:20.225103Z"
    }
   },
   "cell_type": "code",
   "source": [
    "pred = torch.argmax(logits, dim=-1)  # 计算某一维度最节接近的结果\n",
    "print(pred)"
   ],
   "id": "5639334e126509d5",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([0, 0, 1, 0, 0])\n"
     ]
    }
   ],
   "execution_count": 12
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:27:20.256319Z",
     "start_time": "2025-08-13T12:27:20.243530Z"
    }
   },
   "cell_type": "code",
   "source": [
    "print(logits, pred)\n",
    "loss = F.cross_entropy(logits, pred)\n",
    "print(loss)"
   ],
   "id": "367f55790204add0",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[ 2.6585,  2.2138],\n",
      "        [ 1.1108, -0.9596],\n",
      "        [-3.1652,  1.2006],\n",
      "        [-1.3272, -1.5151],\n",
      "        [ 4.7086, -2.5634]], grad_fn=<CatBackward0>) tensor([0, 0, 1, 0, 0])\n",
      "tensor(0.2462, grad_fn=<NllLossBackward0>)\n"
     ]
    }
   ],
   "execution_count": 13
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:27:20.282756Z",
     "start_time": "2025-08-13T12:27:20.267445Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# cross_entropy 等价于\n",
    "print(-probs.log()[range(5), pred].mean())\n",
    "# 把每一个预测的特征取对数，并把正确的预测结果相加求平均。\n",
    "# 这里我想要讨论一下\n",
    "# -probs.log()[range(5), pred] 与 -probs.log()[:, pred] 的区别\n",
    "# -probs.log()[range(5), pred] 是对 (0, 1, 2, 3, 4) 这四行，每一行取第 pred 个数据\n",
    "# -probs.log()[:, pred] 中代表的是 对于全部行的数据，取第 pred 个列组成一个新数据"
   ],
   "id": "b7c993b1c3848ce2",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor(0.2462, grad_fn=<NegBackward0>)\n"
     ]
    }
   ],
   "execution_count": 14
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:30:11.370938Z",
     "start_time": "2025-08-13T12:30:11.288011Z"
    }
   },
   "cell_type": "code",
   "source": [
    "### 生成测试数据\n",
    "from sklearn.datasets import make_blobs\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "data = make_blobs(200, centers=[[-2, 2], [2, 2]])\n",
    "x, y = data\n",
    "\n",
    "print(x, y)\n",
    "plt.scatter(x[:, 0], x[:, 1])"
   ],
   "id": "1b92dbacff63daa7",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 2.72662392  0.97448618]\n",
      " [-2.86541183  3.10777088]\n",
      " [-0.99719247  3.21520395]\n",
      " [-0.84641559  1.76552209]\n",
      " [ 1.45631298  4.08613823]\n",
      " [-2.28994486  4.74232574]\n",
      " [ 1.35751138  1.71506845]\n",
      " [ 1.70271437  1.71770465]\n",
      " [-1.73658497  3.24701379]\n",
      " [-2.10284821  1.27344947]\n",
      " [-1.95873861  2.50885771]\n",
      " [-1.16432603  2.62473339]\n",
      " [-1.08681167  0.75859495]\n",
      " [-1.60602147  0.98622737]\n",
      " [-2.16120058  1.5266393 ]\n",
      " [-0.81858045  1.23274886]\n",
      " [ 1.23688289  2.94784946]\n",
      " [ 2.11658054  1.67313667]\n",
      " [ 1.47309209  2.59013898]\n",
      " [-3.33255432  3.75079993]\n",
      " [ 2.10063843  3.11153915]\n",
      " [-2.73292419  2.29440933]\n",
      " [ 2.83503252  2.28912891]\n",
      " [ 2.06077841  0.64035506]\n",
      " [ 3.01433669  2.89233305]\n",
      " [-1.34199664  2.25506832]\n",
      " [-0.72741638  2.0260711 ]\n",
      " [ 1.74454272  2.90032646]\n",
      " [-2.45745011  2.03057777]\n",
      " [-2.96917294  3.69383725]\n",
      " [ 1.62810401  0.7509505 ]\n",
      " [-3.49172346  1.39242185]\n",
      " [ 1.41958216  1.28839776]\n",
      " [ 0.6823805   2.29244345]\n",
      " [ 3.54162986  0.12550742]\n",
      " [ 1.38834804  0.81803952]\n",
      " [ 2.81550256  3.94012539]\n",
      " [-2.00328173  1.65810268]\n",
      " [ 1.29838915  1.71951558]\n",
      " [-1.82564048  1.88136877]\n",
      " [ 1.82427511  2.86335209]\n",
      " [ 1.78161063  1.44488905]\n",
      " [-0.65444687  2.30013142]\n",
      " [-0.71369666  3.76066236]\n",
      " [ 1.12131465  2.10291782]\n",
      " [ 0.26242024  2.52887458]\n",
      " [-3.09280609  1.33829866]\n",
      " [ 2.26689927  1.92996093]\n",
      " [ 1.93085585  2.18390459]\n",
      " [-1.50597907  3.78456908]\n",
      " [ 1.3922781   0.7048707 ]\n",
      " [-0.81664452  2.79018481]\n",
      " [-2.02389101  2.75990868]\n",
      " [ 2.43808977  0.56306789]\n",
      " [-3.02205603  3.99786921]\n",
      " [ 1.33597911  2.06323248]\n",
      " [ 1.09375002  2.18870612]\n",
      " [ 2.001204    3.00384109]\n",
      " [-2.10843167  2.7232995 ]\n",
      " [ 2.05402423  3.97002561]\n",
      " [-3.30067616  1.87259225]\n",
      " [-1.99054504  1.08110297]\n",
      " [-3.76096546  3.72130201]\n",
      " [-1.51483928  0.85172487]\n",
      " [-2.57275678  0.35603965]\n",
      " [-3.08677513  1.7257926 ]\n",
      " [-0.99292846  1.26310308]\n",
      " [ 0.79881895  2.33766676]\n",
      " [-1.65604262  1.89291496]\n",
      " [-1.16549898  2.35685   ]\n",
      " [ 1.34640542  1.34898195]\n",
      " [-1.50757776  0.62206151]\n",
      " [-1.62352882  1.96135569]\n",
      " [ 3.20580325  1.4207395 ]\n",
      " [-2.37229912  2.89282643]\n",
      " [ 0.19296377  2.85573614]\n",
      " [-1.76018654  1.75412914]\n",
      " [-2.1964404   1.76027646]\n",
      " [ 2.89866812  1.49053197]\n",
      " [ 2.38746317  3.33036708]\n",
      " [-1.83098124  2.88416365]\n",
      " [ 0.6705321  -0.11263396]\n",
      " [-1.87774059  1.05222232]\n",
      " [-2.30106632  0.10387645]\n",
      " [-1.82459567  0.70770553]\n",
      " [ 1.54574452  2.14230015]\n",
      " [ 2.23798203  1.63143548]\n",
      " [ 2.519568    1.09456913]\n",
      " [-0.8390568   0.04216443]\n",
      " [ 1.873091    3.39275272]\n",
      " [ 1.79388101  3.26386259]\n",
      " [-2.38139598  1.69169629]\n",
      " [ 1.39345517  1.01664173]\n",
      " [ 2.03854314  0.83846171]\n",
      " [-2.87027785  1.56778294]\n",
      " [ 2.4587687   2.05675383]\n",
      " [-1.97609684  3.54045141]\n",
      " [ 0.41297372  1.71850792]\n",
      " [ 2.44969238  3.1226038 ]\n",
      " [-2.2307317   2.22580832]\n",
      " [ 1.93065582  2.50484722]\n",
      " [ 2.3875445   2.59853176]\n",
      " [ 2.82535782  3.32481392]\n",
      " [-1.64341733  2.60306446]\n",
      " [ 2.01715892  2.78693325]\n",
      " [ 3.6273099   1.48769567]\n",
      " [ 0.50164548  2.81878428]\n",
      " [-1.63305081  3.49495386]\n",
      " [ 1.74895625  2.17413922]\n",
      " [ 1.79015651  1.99835378]\n",
      " [ 3.16461463  1.9970873 ]\n",
      " [-1.84583808  1.32904421]\n",
      " [-0.63708377  2.2658849 ]\n",
      " [-0.44271353  1.17694744]\n",
      " [ 1.06055461  2.67901812]\n",
      " [ 1.41037569  1.14068252]\n",
      " [-1.21687633  2.86962811]\n",
      " [ 1.01344867  2.75042909]\n",
      " [-0.8303447   0.86797993]\n",
      " [ 0.96505974  1.40856319]\n",
      " [-0.81786547  0.81781601]\n",
      " [-1.24571744  2.88017656]\n",
      " [-1.74036293  2.46990449]\n",
      " [-2.21930917  0.35616199]\n",
      " [-1.06651015  3.2425913 ]\n",
      " [-1.74089336  2.65121142]\n",
      " [ 2.78183026  5.29550069]\n",
      " [ 0.71996413  2.28690077]\n",
      " [ 0.78855014  2.30681706]\n",
      " [ 1.9608684   1.23375191]\n",
      " [ 2.10941161  1.50013616]\n",
      " [-0.10909771  2.50626799]\n",
      " [ 1.82819731  1.68147962]\n",
      " [-0.4369131   1.04525472]\n",
      " [ 3.11899274  0.79513084]\n",
      " [ 2.90948466  1.23283111]\n",
      " [-2.73765266  0.26800416]\n",
      " [ 1.45989483  2.206736  ]\n",
      " [-1.63784245  1.89285638]\n",
      " [-2.66552226  0.47195505]\n",
      " [ 1.69244846  2.38504733]\n",
      " [-3.44490822  1.29730858]\n",
      " [-1.97845122  2.04788108]\n",
      " [-0.99688893  1.02264437]\n",
      " [ 1.99689595  2.78210457]\n",
      " [ 3.06419173  2.43549997]\n",
      " [ 1.95214921  4.02393548]\n",
      " [ 2.39288833  2.11501459]\n",
      " [-1.58884005  1.22106365]\n",
      " [ 2.87791518  1.51698871]\n",
      " [-1.99469721 -0.07336172]\n",
      " [-0.95168386  1.3718868 ]\n",
      " [ 1.32996365  1.84082216]\n",
      " [ 1.78886652  1.17496799]\n",
      " [-2.30117124  0.64426481]\n",
      " [ 3.34269978  2.53333455]\n",
      " [-2.23781056  2.12756091]\n",
      " [-2.20205533  1.74198176]\n",
      " [ 1.28721743  2.51897039]\n",
      " [-2.09037169  1.64379911]\n",
      " [-1.27926249  1.0969153 ]\n",
      " [-3.47722781  1.14474128]\n",
      " [ 2.48247889  1.95385478]\n",
      " [-2.57323182  2.65856996]\n",
      " [ 1.62046948  2.31917277]\n",
      " [ 2.97778073  1.75609572]\n",
      " [-0.63017592  2.84867808]\n",
      " [ 3.58799958  3.62858591]\n",
      " [ 3.450077    2.8965338 ]\n",
      " [-0.88286947  3.02185784]\n",
      " [ 2.09862398  2.08743203]\n",
      " [ 3.36542129  2.5456383 ]\n",
      " [-2.9412962   0.79225784]\n",
      " [-2.30621128  0.71003757]\n",
      " [-1.53757521  2.64551871]\n",
      " [ 1.91996068  0.08890404]\n",
      " [ 2.88512423  1.88300964]\n",
      " [ 2.73312197  1.62681271]\n",
      " [ 3.07879289  2.01955322]\n",
      " [ 1.6802212   1.72678383]\n",
      " [-3.74899563 -0.22199795]\n",
      " [ 1.3492063   1.62378026]\n",
      " [-0.95532822  0.24000295]\n",
      " [-2.65000159  1.2696491 ]\n",
      " [ 2.11394395  0.26116201]\n",
      " [-0.86418119  0.85677609]\n",
      " [ 2.21481701  2.23008389]\n",
      " [-2.2536291   2.25155387]\n",
      " [-3.39917623  4.01336505]\n",
      " [-3.41777594  0.62824019]\n",
      " [-1.87734093  1.69812119]\n",
      " [-2.14594929  2.62333284]\n",
      " [ 0.56698427  2.14358451]\n",
      " [ 2.27225002 -0.855072  ]\n",
      " [-1.1556638   2.41070811]\n",
      " [-1.74069789  2.45905901]\n",
      " [ 2.69034568  3.0407831 ]\n",
      " [ 3.62323346  1.96893608]\n",
      " [ 2.21600531  2.25785268]\n",
      " [ 0.8066008   1.64647416]] [1 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 1 1 1 0 1 0 1 1 1 0 0 1 0 0 1 0 1 0 1 1 1\n",
      " 0 1 0 1 1 0 0 1 1 0 1 1 0 1 0 0 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 1\n",
      " 0 1 0 0 1 1 0 1 0 0 0 1 1 1 0 1 1 0 1 1 0 1 0 1 1 0 1 1 1 0 1 1 1 0 1 1 1\n",
      " 0 0 0 1 1 1 1 0 1 0 0 0 0 0 0 1 1 1 1 1 0 1 0 1 1 0 1 0 0 1 0 0 0 1 1 1 1\n",
      " 0 1 0 0 1 1 0 1 0 0 1 0 0 0 1 0 1 1 0 1 1 0 1 1 0 0 0 1 1 1 1 1 0 1 0 0 1\n",
      " 0 1 0 0 0 0 0 0 1 0 0 1 1 1 1]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x1b39fc042d0>"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ],
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 17
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:44:19.192032Z",
     "start_time": "2025-08-13T12:42:49.223132Z"
    }
   },
   "cell_type": "code",
   "source": [
    "batch_size = 20\n",
    "max_steps = 2000\n",
    "learning_rate = 0.01\n",
    "\n",
    "\"\"\"\n",
    "x坐标 ↘\n",
    "        [2 * 1] → 正预测\n",
    "        [2 * 1] → 负预测\n",
    "y坐标 ↗\n",
    "\"\"\"\n",
    "\n",
    "lr = LogitRegression(2)\n",
    "lossi = []\n",
    "\n",
    "x, y = torch.tensor(x).float(), torch.tensor(y)\n",
    "\n",
    "for t in range(max_steps):\n",
    "    ix = (t * batch_size) % len(x)\n",
    "    xx = x[ix: ix + batch_size]\n",
    "    yy = y[ix: ix + batch_size]\n",
    "\n",
    "    logits = lr(xx)\n",
    "    loss = F.cross_entropy(logits, yy)\n",
    "    loss.backward()\n",
    "\n",
    "    with torch.no_grad():\n",
    "        for p in lr.parameters():\n",
    "            p -= learning_rate * p.grad\n",
    "            p.grad = None\n",
    "\n",
    "    if t % 200 == 0:\n",
    "        print(f'step: {t}, loss: {loss.item()}')\n",
    "\n",
    "    lossi.append(loss.item())\n",
    "\n"
   ],
   "id": "eec0d02e13bf75e8",
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\lovep\\AppData\\Local\\Temp\\ipykernel_41932\\1388652094.py:15: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.detach().clone() or sourceTensor.detach().clone().requires_grad_(True), rather than torch.tensor(sourceTensor).\n",
      "  x, y = torch.tensor(x).float(), torch.tensor(y)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "step: 0, loss: 3.614760637283325\n",
      "step: 200, loss: 0.170270174741745\n",
      "step: 400, loss: 0.09395795315504074\n",
      "step: 600, loss: 0.06800124049186707\n",
      "step: 800, loss: 0.0543740876019001\n",
      "step: 1000, loss: 0.04584439843893051\n",
      "step: 1200, loss: 0.039956361055374146\n",
      "step: 1400, loss: 0.03562803938984871\n",
      "step: 1600, loss: 0.03230324015021324\n",
      "step: 1800, loss: 0.02966490015387535\n"
     ]
    }
   ],
   "execution_count": 24
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-08-13T12:34:16.142698Z",
     "start_time": "2025-08-13T12:34:16.065299Z"
    }
   },
   "cell_type": "code",
   "source": "plt.plot(lossi)",
   "id": "64b653573c125444",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x1b3a2e090d0>]"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ],
      "image/png": "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fenSpV5trOqfdPZteNNNN51W/5VXXunVpqtuQ0kt/k7abDY99NBDnjadeRu2Zb/QUd+dGzdu1Pjx4+V0OjV48GA988wzX70DpodavXq1CQoKMqtWrTKff/65ufXWW01kZKQpKiqyurSzmj59unn66afN9u3bTXZ2trnqqqtMv379THV1tafNJZdcYm699VZz+PBhz6OiosLzelNTkxk5cqTJyMgwW7ZsMa+//rqJiYkxixYtsqJLXu69915z/vnne9VeUlLief22224zKSkpJjMz02zatMlccMEF5sILL/S83pn7ZowxxcXFXn1bt26dkWQ2bNhgjOma2+711183v/71r83LL79sJJlXXnnF6/WlS5eaiIgI8+qrr5qtW7eaa665xgwYMMAcO3bM0+bKK680Y8aMMR9++KF59913zeDBg83111/veb2iosLEx8ebG2+80Wzfvt0899xzJiQkxPzlL3+xtH/l5eUmIyPDPP/882bnzp0mKyvLTJ482UyYMMHrPfr372/uv/9+r+3a/HfWyv6drY/GGDNnzhxz5ZVXetVfVlbm1aarbkNjjFe/Dh8+bFatWmVsNpvZs2ePp01n3oZt2S90xHfn3r17TWhoqFmwYIHZsWOHefTRR43D4TBr1679SvX32DAyefJkM2/ePM/PLpfLJCUlmSVLllhY1bkpLi42kszbb7/tWXbJJZeY+fPnt7rO66+/bux2uyksLPQse/zxx014eLipr6/3Zblnde+995oxY8a0+Fp5ebkJDAw0L774omfZF198YSSZrKwsY0zn7ltL5s+fbwYNGmTcbrcxpmtvO2PMaV/0brfbJCQkmIceesizrLy83DidTvPcc88ZY4zZsWOHkWQ++eQTT5s33njD2Gw2c/DgQWOMMY899piJiory6uPChQvN0KFDfdwjby3tyE718ccfG0lm//79nmX9+/c3jzzySKvrdJb+GdNyH+fMmWO+8Y1vtLpOd9uG3/jGN8zXvvY1r2VdaRueul/oqO/OX/7yl+b888/3+qxZs2aZ6dOnf6V6e+Q0TUNDgzZv3qyMjAzPMrvdroyMDGVlZVlY2bmpqKiQJEVHR3st/+c//6mYmBiNHDlSixYtUm1tree1rKwsjRo1SvHx8Z5l06dPV2VlpT7//HP/FH4Gu3fvVlJSkgYOHKgbb7xR+fn5kqTNmzersbHRa9sNGzZM/fr182y7zt635hoaGvSPf/xDP/zhD71uAtmVt92p9u3bp8LCQq9tFhERobS0NK9tFhkZqYkTJ3raZGRkyG6366OPPvK0ufjiixUUFORpM336dOXk5Ojo0aN+6k3bVFRUyGazKTIy0mv50qVL1adPH40bN04PPfSQ1/B3V+jfxo0bFRcXp6FDh+r222/XkSNHPK91p21YVFSkNWvW6Oabbz7tta6yDU/dL3TUd2dWVpbXe5xs81X3nV3iRnkdrbS0VC6Xy+svXJLi4+O1c+dOi6o6N263Wz/96U81ZcoUjRw50rP8hhtuUP/+/ZWUlKRt27Zp4cKFysnJ0csvvyxJKiwsbLH/J1+zUlpamp555hkNHTpUhw8f1n333aepU6dq+/btKiwsVFBQ0Glf8vHx8Z66O3PfTvXqq6+qvLxcN910k2dZV952LTlZU0s1N99mcXFxXq8HBAQoOjraq82AAQNOe4+Tr0VFRfmk/vaqq6vTwoULdf3113vddOx///d/NX78eEVHR+uDDz7QokWLdPjwYS1btkxS5+/flVdeqeuuu04DBgzQnj179Ktf/UozZsxQVlaWHA5Ht9qGf/vb3xQWFqbrrrvOa3lX2YYt7Rc66ruztTaVlZU6duyYQkJCzqnmHhlGupN58+Zp+/bteu+997yW/+hHP/I8HzVqlBITEzVt2jTt2bNHgwYN8neZ7TJjxgzP89GjRystLU39+/fXCy+8cM7/0Durp556SjNmzFBSUpJnWVfedj1dY2Ojvvvd78oYo8cff9zrtQULFniejx49WkFBQfqf//kfLVmypEtcZvx73/ue5/moUaM0evRoDRo0SBs3btS0adMsrKzjrVq1SjfeeKOCg4O9lneVbdjafqEz65HTNDExMXI4HKcdRVxUVKSEhASLqmq/O+64Q//5z3+0YcMG9e3b94xt09LSJEm5ubmSpISEhBb7f/K1ziQyMlLnnXeecnNzlZCQoIaGBpWXl3u1ab7tukrf9u/fr/Xr1+uWW245Y7uuvO2kL2s60+9bQkKCiouLvV5vampSWVlZl9muJ4PI/v37tW7durPeij0tLU1NTU3Ky8uT1Pn7d6qBAwcqJibG699lV9+GkvTuu+8qJyfnrL+XUufchq3tFzrqu7O1NuHh4V/pP4s9MowEBQVpwoQJyszM9Cxzu93KzMxUenq6hZW1jTFGd9xxh1555RW99dZbpw0LtiQ7O1uSlJiYKElKT0/XZ5995vXlcfILdMSIET6p+1xVV1drz549SkxM1IQJExQYGOi17XJycpSfn+/Zdl2lb08//bTi4uJ09dVXn7FdV952kjRgwAAlJCR4bbPKykp99NFHXtusvLxcmzdv9rR566235Ha7PWEsPT1d77zzjhobGz1t1q1bp6FDh1o+vH8yiOzevVvr169Xnz59zrpOdna27Ha7Z2qjM/evJQcOHNCRI0e8/l125W140lNPPaUJEyZozJgxZ23bmbbh2fYLHfXdmZ6e7vUeJ9t85X3nVzr8tQtbvXq1cTqd5plnnjE7duwwP/rRj0xkZKTXUcSd1e23324iIiLMxo0bvU4xq62tNcYYk5uba+6//36zadMms2/fPvPaa6+ZgQMHmosvvtjzHidP4briiitMdna2Wbt2rYmNje0Up7/eeeedZuPGjWbfvn3m/fffNxkZGSYmJsYUFxcbY46fntavXz/z1ltvmU2bNpn09HSTnp7uWb8z9+0kl8tl+vXrZxYuXOi1vKtuu6qqKrNlyxazZcsWI8ksW7bMbNmyxXM2ydKlS01kZKR57bXXzLZt28w3vvGNFk/tHTdunPnoo4/Me++9Z4YMGeJ1Wmh5ebmJj483P/jBD8z27dvN6tWrTWhoqF9OmzxT/xoaGsw111xj+vbta7Kzs71+J0+egfDBBx+YRx55xGRnZ5s9e/aYf/zjHyY2NtbMnj27U/TvbH2sqqoyP//5z01WVpbZt2+fWb9+vRk/frwZMmSIqaur87xHV92GJ1VUVJjQ0FDz+OOPn7Z+Z9+GZ9svGNMx350nT+39xS9+Yb744guzYsUKTu39qh599FHTr18/ExQUZCZPnmw+/PBDq0tqE0ktPp5++mljjDH5+fnm4osvNtHR0cbpdJrBgwebX/ziF17XqjDGmLy8PDNjxgwTEhJiYmJizJ133mkaGxst6JG3WbNmmcTERBMUFGSSk5PNrFmzTG5uruf1Y8eOmR//+McmKirKhIaGmm9+85vm8OHDXu/RWft20ptvvmkkmZycHK/lXXXbbdiwocV/k3PmzDHGHD+995577jHx8fHG6XSaadOmndb3I0eOmOuvv9707t3bhIeHm7lz55qqqiqvNlu3bjUXXXSRcTqdJjk52SxdutTy/u3bt6/V38mT147ZvHmzSUtLMxERESY4ONgMHz7cPPDAA147civ7d7Y+1tbWmiuuuMLExsaawMBA079/f3Prrbee9p+3rroNT/rLX/5iQkJCTHl5+Wnrd/ZteLb9gjEd9925YcMGM3bsWBMUFGQGDhzo9RnnynaiEwAAAJbokceMAACAzoMwAgAALEUYAQAAliKMAAAASxFGAACApQgjAADAUoQRAABgKcIIAACwFGEEAABYijACAAAsRRgBAACWIowAAABL/f+PpupEgOo0xAAAAABJRU5ErkJggg=="
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 19
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
